package com.zxd.interview.beabug.ssl;


import cn.hutool.core.exceptions.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Objects;

@Slf4j
@Component
public class SSLHttpClientUtil {

    // 根据支持的TLS版本调整即可
    private static final String[] SUPPORT_TLS_VERSION = new String[]{"TLSv1.2", "TLSv1.3"};
    //
    private static final String PKCS12 = "PKCS12";

    public String sendCommon(String json, String requestUrl) {
        KeyStore keyStore = null;
        try {
            keyStore = KeyStore.getInstance(PKCS12);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        }
        // 加载 cert 证书
        String certFilePath = "";
        try {
            keyStore.load(Files.newInputStream(
                            new File(certFilePath).toPath()),
                    new char[]{'1', '2','3','4','5','6'});
        } catch (IOException e) {
            log.warn("【SSLHttpClientUtil】读取文件失败，读取文件地址为：{}", certFilePath);
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            log.info("【SSLHttpClientUtil】算法异常 {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        } catch (CertificateException e) {
            log.info("【SSLHttpClientUtil】证书异常 {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        }

        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContexts.custom()
                    //忽略掉对服务器端证书的校验
                    .loadTrustMaterial((TrustStrategy) (chain, authType) -> true)
                    //加载服务端提供的truststore(如果服务器提供truststore的话就不用忽略对服务器端证书的校验了)
                    .loadTrustMaterial(new File("D:\\truststore.jks"), "123456".toCharArray(),
                            new TrustSelfSignedStrategy())
                    // 加载证书的部分放到单独的代码块
//                    .loadKeyMaterial(keyStore, acsConfig.getCertFilePassWord().toCharArray())
                    .build();
        } catch (NoSuchAlgorithmException e) {
            log.info("【SSLHttpClientUtil】算法不存在 {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        } catch (KeyManagementException | KeyStoreException | CertificateException | IOException e) {
            log.info("【SSLHttpClientUtil】密钥管理异常 {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        }
        SSLConnectionSocketFactory sslConnectionSocketFactory =
                new SSLConnectionSocketFactory(
                        sslcontext,
                        SUPPORT_TLS_VERSION,
                        null,
                        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .build();
        HttpEntity responseEntity = null;
        try {

            HttpPost httpPost = new HttpPost(requestUrl);
            httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
            httpPost.setHeader("Accept", "application/json");
            StringEntity stringEntity = new StringEntity(json, "UTF-8");
            stringEntity.setContentType("text/json");
            httpPost.setEntity(stringEntity);
            log.info("【SSLHttpClientUtil】请求 URL 为：" + requestUrl);
            if(log.isDebugEnabled()){
                log.debug("【SSLHttpClientUtil】请求行信息为：" + httpPost.getRequestLine());
            }
            log.info("【SSLHttpClientUtil】请求体为：：" + json);
            CloseableHttpResponse response = null;
            response = httpclient.execute(httpPost);
            if(Objects.isNull(response)){
                throw new RuntimeException("response 返回内容为 null");
            }
            if(log.isDebugEnabled()){
                log.debug("【SSLHttpClientUtil】响应状态码 {}", response.getStatusLine());
            }
            responseEntity = response.getEntity();
            String resJson = IOUtils.toString(responseEntity.getContent(), StandardCharsets.UTF_8);
            log.info("【SSLHttpClientUtil】响应内容 {}", resJson);
            return resJson;
        } catch (ClientProtocolException e) {
            log.warn("【SSLHttpClientUtil】HTTP请求异常 {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        } catch (IOException e) {
            log.warn("【SSLHttpClientUtil】IOException {}", ExceptionUtil.getMessage(e));
            throw new RuntimeException(e);
        } finally {
            try {
                // 释放IO
                if(Objects.nonNull(responseEntity)){
                    EntityUtils.consume(responseEntity);
                }

            } catch (IOException e) {
                log.warn("【SSLHttpClientUtil】EntityUtils.consume 异常 {}", ExceptionUtil.getMessage(e));
                throw new RuntimeException(e);
            }
            try {
                if (Objects.nonNull(httpclient)) {
                    httpclient.close();
                }
            } catch (IOException e) {
                log.warn("【SSLHttpClientUtil】httpclient 关闭异常 {}", ExceptionUtil.getMessage(e));
                throw new RuntimeException(e);
            }
        }
    }
}
